package udpSve;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.security.acl.LastOwnerException;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

public class UDPNode extends AbstractNodeKomunikacija {

	private volatile int requestID = 1;
	private List<Entry<InetAddress, Integer>> poslednjih10Klijenata,
			sviServeri;
	private Map<Integer, String> zahtevi;
	private volatile String role;
	private String opseg;
	ArrayList<Entry<ChunkState, Long>> chunkStates;

	public UDPNode(String opseg, int mojPort,
			List<Entry<InetAddress, Integer>> poslednjih10Klijenata) {
		super(mojPort);
		System.out.println("PRAVIM NOVI UDPNODE");
		this.poslednjih10Klijenata = poslednjih10Klijenata;
		this.zahtevi = new ConcurrentHashMap<Integer, String>();
		this.sviServeri = new ArrayList<Map.Entry<InetAddress, Integer>>();
		this.opseg = opseg;
	}

	public void start() {
		System.out.println("UDP NODE START");
		startRecieving();
		obratiSePoslednjih10Klijenata();
	}

	private void obratiSePoslednjih10Klijenata() {
		System.out.println(poslednjih10Klijenata);
		System.out.println("POSLEDNJIH 10 SIZE: "
				+ poslednjih10Klijenata.size());
		if (poslednjih10Klijenata.size() == 0) {
			UDPServerNode udpsn = new UDPServerNode(null, requestID, opseg,
					listenPort, sviServeri);
			stopRecieving();
			udpsn.start();
			return;
		}
		String komanda = Commmands.NEW_NODE;
		String teloPoruke = "EMPTY";
		while (true) {// stalno pokusavaj...
			for (Entry<InetAddress, Integer> currentClient : poslednjih10Klijenata) {
				sendPaket(currentClient.getKey(), currentClient.getValue(),
						requestID, komanda, teloPoruke);
				zahtevi.put(requestID, Commmands.NEW_NODE_RESPONSE);

				if (waitForResponse(requestID)) {
					if (role.equals(Commmands.ROLE_SERVER)) {
						UDPServerNode udpsn = new UDPServerNode(chunkStates,
								requestID + 1, opseg, listenPort, sviServeri);
						stopRecieving();
						udpsn.start();
						return;
					} else if (role.equals(Commmands.ROLE_CLIENT)) {
						UDPClientNode udpcn = new UDPClientNode(requestID + 1,
								opseg, listenPort, sviServeri);
						stopRecieving();
						udpcn.start();
						return;
					}
					requestID++;
					return;
				} else {
					System.out.println("WARN: FAILED ONECE");
				}
				zahtevi.remove(requestID);
				requestID++;
			}
		}
		// System.err.println("SJEBAO SAM SE NIKO NECE DA MI ODGOVORI JA SAM UGLJESA GEJ");
	}

	private boolean waitForResponse(int requestID) {
		long startTime = System.currentTimeMillis();
		long treunutnoVreme = startTime;
		while ((treunutnoVreme - startTime) < 5000
				&& zahtevi.containsKey(requestID)) {
			try {
				Thread.sleep(100);
				treunutnoVreme = System.currentTimeMillis();

			} catch (InterruptedException e) {
				e.printStackTrace();
				return false;
			}
		}
		return !zahtevi.containsKey(requestID);
	}

	@Override
	protected void obradiPaket(InetAddress recieveAddress, int recievePort,
			int requestID, String komanda, String telo) {
		// nadji u mapi ako ima, obradi ga i izbaci iz mape
		if (komanda.equals(zahtevi.get(requestID))) { //
			// telo ce biti rola i lista svih servera
			sviServeri = new ArrayList<Entry<InetAddress, Integer>>();
			// telo: rola;host;port;entry...
			String[] split = telo.split(";");
			role = split[0];
			System.out.println("ROLA: " + role + "\nCITAM SVE SERVERE...");
			int brojServera = Integer.parseInt(split[1]);

			int j = 2;
			for (int i = 0; i < brojServera; i += 1) {

				try {
					sviServeri
							.add(new AbstractMap.SimpleEntry<InetAddress, Integer>(
									InetAddress.getByName(split[j]), Integer
											.parseInt(split[j + 1])));
				} catch (NumberFormatException e) {
					e.printStackTrace();
				} catch (UnknownHostException e) {
					e.printStackTrace();
				}
				j += 2;
			}
			System.out.println(sviServeri);
			System.out.println("CITAM CHUNK STATEOVE");

			int brojChunkova = Integer.parseInt(split[j]);
			chunkStates = new ArrayList<Map.Entry<ChunkState, Long>>();
			j++;
			for (int i = 0; i < brojChunkova; i += 1) {

				try {
					chunkStates
							.add(new AbstractMap.SimpleEntry<ChunkState, Long>(
									ChunkState.valueOf(split[j]), Long
											.parseLong(split[j + 1])));
				} catch (NumberFormatException e) {
					e.printStackTrace();
				}
				j += 2;
			}
			System.out.println(chunkStates);

			zahtevi.remove(requestID);
		}

	}

}
